﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using Mbs.SmartParts;

namespace Mbs.Windows
{
    [ToolboxItem(false)]
    public class BaseStackStrip : ToolStrip
    {
        private ToolStripProfessionalRenderer _pr = null;

        #region Public API
        public BaseStackStrip()
        {
            // Check Dock
            this.Dock = DockStyle.Fill;
            this.GripStyle = ToolStripGripStyle.Hidden;
            this.Margin = new Padding(0);
            this.CanOverflow = false;
            this.AutoSize = false;

            // Set renderer - override background painting
            SetRenderer();

            // Setup Fonts
            OnSetFonts();

            // Track Preference Changes
            Microsoft.Win32.SystemEvents.UserPreferenceChanged += new Microsoft.Win32.UserPreferenceChangedEventHandler(StackStrip_UserPreferenceChanged);
        }
        #endregion

        #region Protected API
        protected virtual void OnSetRenderer(ToolStripProfessionalRenderer pr)
        {
            // Handled by sub-classes
        }

        protected virtual void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
        {
            if (StackStripRenderer != null)
            {
                // Setup colors from the provided renderer
                Color start = StackStripRenderer.ColorTable.ToolStripGradientMiddle;
                Color end = StackStripRenderer.ColorTable.ToolStripGradientEnd;

                // Size to paint
                Rectangle bounds = new Rectangle(Point.Empty, e.ToolStrip.Size);

                // Make sure we need to do work
                if ((bounds.Width > 0) && (bounds.Height > 0))
                {
                    using (Brush b = new LinearGradientBrush(bounds, start, end, LinearGradientMode.Vertical))
                    {
                        e.Graphics.FillRectangle(b, bounds);
                    }
                }

                // Draw border
                //e.Graphics.DrawRectangle(SystemPens.ControlDarkDark, bounds);
                e.Graphics.DrawLine(SystemPens.ControlDarkDark, bounds.X, bounds.Y, bounds.Width - 1, bounds.Y);
                e.Graphics.DrawLine(SystemPens.ControlDarkDark, bounds.X, bounds.Y, bounds.X, bounds.Height - 1);
                e.Graphics.DrawLine(SystemPens.ControlDarkDark, bounds.X + bounds.Width - 1, bounds.Y, bounds.X + bounds.Width - 1, bounds.Height - 1);
            }
        }

        protected ToolStripProfessionalRenderer StackStripRenderer
        {
            get { return _pr; }
        }

        protected virtual void OnSetFonts()
        {
            // Base off system fonts
        }
        #endregion

        #region Overrides
        protected override void OnRendererChanged(EventArgs e)
        {
            // Call the base
            base.OnRendererChanged(e);

            // Work around bug with setting renderer in the constructor
            SetRenderer();
        }
        #endregion

        #region Private API
        private void SetRenderer()
        {
            // Set renderer - override background painting
            if ((this.Renderer is ToolStripProfessionalRenderer) && (this.Renderer != _pr))
            {
                if (_pr == null)
                {
                    // Only swap out if we're setup to use a professional renderer
                    _pr = new ToolStripProfessionalRenderer();

                    // Square edges
                    _pr.RoundedEdges = false;

                    // Improve painting (use our colors)
                    _pr.RenderToolStripBackground += new ToolStripRenderEventHandler(BaseStackStrip_RenderToolStripBackground);

                    // Call overridable method
                    OnSetRenderer(_pr);
                }

                // User our renderer
                this.Renderer = _pr;
            }
        }
        #endregion

        #region Event Handlers
        void BaseStackStrip_RenderToolStripBackground(object sender, ToolStripRenderEventArgs e)
        {
            // Call override
            OnRenderToolStripBackground(e);
        }

        private void StackStrip_UserPreferenceChanged(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e)
        {
            // Reset Font
            OnSetFonts();
        }
        #endregion
    }

    public class StackStrip : BaseStackStrip
    {
        const int DEFAULT_ITEM_COUNT = 4;
        protected event EventHandler _itemHeightChanged;

        private ToolStripButton _last = null;
        private bool _ignore = false;
        private Font _font;

        #region Public API
        public StackStrip()
            : base()
        {
            // Check Dock
            this.LayoutStyle = ToolStripLayoutStyle.VerticalStackWithOverflow;
        }

        public int ItemCount
        {
            get { return this.Items.Count; }
        }

        public int InitialDisplayCount
        {
            get { return (Math.Min(ItemCount, DEFAULT_ITEM_COUNT)); }
        }

        public event EventHandler ItemHeightChanged
        {
            add { _itemHeightChanged += new EventHandler(value); }
            remove { _itemHeightChanged -= new EventHandler(value); }
        }

        public int ItemHeight
        {
            get { return ((ItemCount > 0) ? this.Items[0].Height : 0); }
        }
        #endregion

        #region Protected API
        protected override void OnSetRenderer(ToolStripProfessionalRenderer pr)
        {
            // Do base work
            base.OnSetRenderer(pr);

            // Button Painting
            pr.RenderButtonBackground += new ToolStripItemRenderEventHandler(StackStrip_RenderButtonBackground);
        }

        protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
        {
            // Use base rendering
        }

        protected override void OnSetFonts()
        {
            // Call base
            _font = new Font(SystemFonts.IconTitleFont, FontStyle.Bold);

            // Update if different
            if (this.Font != _font)
            {
                this.Font = _font;

                // Notify container
                OnItemHeightChanged(EventArgs.Empty);
            }
        }

        protected virtual void OnItemHeightChanged(EventArgs e)
        {
            if (null != _itemHeightChanged)
            {
                _itemHeightChanged(this, e);
            }
        }

        protected override void OnItemAdded(ToolStripItemEventArgs e)
        {
            ToolStripButton button = e.Item as ToolStripButton;

            if (null != button)
            {
                // Hook Click
                button.CheckedChanged += new EventHandler(StackStripButton_CheckedChanged);
            }
        }
        #endregion

        #region Event Handlers
        void StackStrip_RenderButtonBackground(object sender, ToolStripItemRenderEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle bounds = new Rectangle(Point.Empty, e.Item.Size);

            Color gradientBegin = StackStripRenderer.ColorTable.ImageMarginGradientMiddle;
            Color gradientEnd = StackStripRenderer.ColorTable.ImageMarginGradientEnd;

            ToolStripButton button = e.Item as ToolStripButton;
            if (button.Pressed || button.Checked)
            {
                gradientBegin = StackStripRenderer.ColorTable.ButtonPressedGradientBegin;
                gradientEnd = StackStripRenderer.ColorTable.ButtonPressedGradientEnd;
            }
            else if (button.Selected)
            {
                gradientBegin = StackStripRenderer.ColorTable.ButtonSelectedGradientBegin;
                gradientEnd = StackStripRenderer.ColorTable.ButtonSelectedGradientEnd;
            }

            // Draw Button Background
            using (Brush b = new LinearGradientBrush(bounds, gradientBegin, gradientEnd, LinearGradientMode.Vertical))
            {
                g.FillRectangle(b, bounds);
            }

            // Draw Outilne
            e.Graphics.DrawRectangle(SystemPens.ControlDarkDark, bounds);
        }

        void StackStripButton_CheckedChanged(object sender, EventArgs e)
        {
            ToolStripButton button = (sender as ToolStripButton);

            // Should never be null - but in case someone adds a label
            if (_ignore || (null != button))
            {
                if (button.Checked)
                {
                    if ((_last != button) && (null != _last))
                    {
                        // Unset
                        _ignore = true;
                        _last.Checked = false;
                        _ignore = false;
                    }

                    _last = button;
                }
                else
                {
                    // Make sure something is checked
                    bool foundItem = false;

                    foreach (ToolStripItem item in this.Items)
                    {
                        ToolStripButton btn = (item as ToolStripButton);

                        if (null != btn)
                        {
                            if (btn.Checked)
                            {
                                foundItem = true;
                                break;
                            }
                        }
                    }

                    // Verify
                    if (!foundItem)
                    {
                        // Select the last item
                        _last = button;

                        _ignore = true;
                        button.Checked = true;
                        _ignore = false;
                    }
                }
            }
        }
        #endregion
    }

    public class HeaderStrip : ToolStrip
    {
        private AreaHeaderStyle _headerStyle = AreaHeaderStyle.Large;
        private ToolStripProfessionalRenderer _pr = null;

        #region Public API
        public HeaderStrip()
        {
            // Check Dock
            this.Dock = DockStyle.Top;
            this.GripStyle = ToolStripGripStyle.Hidden;
            this.AutoSize = false;

            // Set renderer - override background painting
            SetRenderer();

            // Track Preference Changes
            Microsoft.Win32.SystemEvents.UserPreferenceChanged += new Microsoft.Win32.UserPreferenceChangedEventHandler(HeaderStrip_UserPreferenceChanged);

            // Setup Headers
            SetHeaderStyle();
        }

        [DefaultValue(AreaHeaderStyle.Large)]
        public AreaHeaderStyle HeaderStyle
        {
            get { return _headerStyle; }
            set
            {
                // Save value
                if (_headerStyle != value)
                {
                    _headerStyle = value;

                    // Set Header Style
                    SetHeaderStyle();
                }
            }
        }
        #endregion

        #region Overrides
        protected override void OnRendererChanged(EventArgs e)
        {
            // Call the base
            base.OnRendererChanged(e);

            // Work around bug with setting renderer in the constructor
            SetRenderer();
        }
        #endregion

        #region Private Implementation
        private void SetHeaderStyle()
        {
            // Get system font
            Font font = SystemFonts.MenuFont;

            if (_headerStyle == AreaHeaderStyle.Large)
            {
                this.Font = new Font("Arial", font.SizeInPoints + 3.75F, FontStyle.Bold);
                this.ForeColor = System.Drawing.Color.White;
            }
            else
            {
                this.Font = font;
                this.ForeColor = System.Drawing.Color.Black;
            }

            // Only way to calculate size
            ToolStripLabel tsl = new ToolStripLabel();
            tsl.Font = this.Font;
            tsl.Text = "I";

            // Set Size
            this.Height = tsl.GetPreferredSize(Size.Empty).Height + 6;
        }

        private void SetRenderer()
        {
            // Set renderer - override background painting
            if ((this.Renderer is ToolStripProfessionalRenderer) && (this.Renderer != _pr))
            {
                if (_pr == null)
                {
                    // Only swap out if we're setup to use a professional renderer
                    _pr = new ToolStripProfessionalRenderer();

                    // Square edges
                    _pr.RoundedEdges = false;

                    // Improve painting (use our colors)
                    _pr.RenderToolStripBackground += new ToolStripRenderEventHandler(Renderer_RenderToolStripBackground);
                }

                // User our renderer
                this.Renderer = _pr;
            }
        }
        #endregion

        #region Event Handlers
        void Renderer_RenderToolStripBackground(object sender, ToolStripRenderEventArgs e)
        {
            Color start;
            Color end;

            if (this.Renderer is ToolStripProfessionalRenderer)
            {
                ToolStripProfessionalRenderer pr = (this.Renderer as ToolStripProfessionalRenderer);

                // Setup colors from the provided renderer
                if (_headerStyle == AreaHeaderStyle.Large)
                {
                    start = pr.ColorTable.OverflowButtonGradientMiddle;
                    end = pr.ColorTable.OverflowButtonGradientEnd;
                }
                else
                {
                    start = pr.ColorTable.MenuStripGradientEnd;
                    end = pr.ColorTable.MenuStripGradientBegin;
                }

                // Size to paint
                Rectangle bounds = new Rectangle(Point.Empty, e.ToolStrip.Size);

                // Make sure we need to do work
                if ((bounds.Width > 0) && (bounds.Height > 0))
                {
                    using (Brush b = new LinearGradientBrush(bounds, start, end, LinearGradientMode.Vertical))
                    {
                        e.Graphics.FillRectangle(b, bounds);
                    }
                }
            }
        }


        private void HeaderStrip_UserPreferenceChanged(object sender, Microsoft.Win32.UserPreferenceChangedEventArgs e)
        {
            SetHeaderStyle();
        }
        #endregion
    }

    #region AreaHeaderStyle
    public enum AreaHeaderStyle
    {
        Large = 0000,
        Small = 0001
    }
    #endregion

    public class OutlookBarSmartPartInfo : SmartPartInfo
    {
        private Image _icon;
        private string _eventTopicName;
        private Color _imageTransparentColor = Color.Empty;
        private double _index = -1.0;

        /// <summary>
        /// Get or set the transparent color of the icon image
        /// </summary>
        public Color ImageTransparentColor
        {
            get { return _imageTransparentColor; }
            set { _imageTransparentColor = value; }
        }

        /// <summary>
        /// Get or set the name of the <see cref="Microsoft.Practices.CompositeUI.EventBroker.EventTopic" /> to be fired when the button is pressed.
        /// </summary>
        public string EventTopicName
        {
            get { return _eventTopicName; }
            set { _eventTopicName = value; }
        }

        /// <summary>
        /// Get or set the icon image to be used in the outlook bar button
        /// </summary>
        public Image Icon
        {
            get { return _icon; }
            set { _icon = value; }
        }

        /// <summary>
        /// Get or set the position index where the button will be inserted relative to the other buttons (The lesser the index, the upper the button will appear)
        /// </summary>        
        public double Index
        {
            get { return this._index; }
            set { this._index = value; }
        }

        public OutlookBarSmartPartInfo()
        { }

        public OutlookBarSmartPartInfo(string title, Image icon)
            : this(title, icon, String.Empty)
        { }

        public OutlookBarSmartPartInfo(string title, Image icon, string eventTopic)
        {
            this.Title = title;
            this._icon = icon;
            this._eventTopicName = eventTopic;
        }

        public OutlookBarSmartPartInfo(string title, Image icon, double index)
        {
            this.Title = title;
            this._icon = icon;
            this._index = index;
        }

        public OutlookBarSmartPartInfo(string title, Image icon, string eventTopic, double index)
        {
            this.Title = title;
            this._icon = icon;
            this._eventTopicName = eventTopic;
            this._index = index;
        }
    }
}
